#作业先完成,才完美
#练习作用域之间的转换
a = 1
b = []
c = 5

def func1():
    a = 2
    b.append(1)
    # UnboundLocalError: local variable 'b' referenced before assignment
    # 如果开打下面注释，那么b在函数内赋值，b变成了局部变量。上一行代码就会报错：局部变量b在分配前被引用
    # b = 3
    global c
    c = 7
    print(f'func1内的局部变量a = {a}')
    print(f'func1内的全局变量b = {b}')
    print(f'func1内的全局变量c = {c}')

def func2():
    b = 3
    # AttributeError: 'int' object has no attribute 'append'
    # b在函数内赋值，则b是局部变量且是int对象，int对象没有append属性
    # b.append(1)
    print(f'func2内的局部变量b = {b}')
    def func3(value):
        nonlocal b
        b = 10 + value
        print(f'func3内的自由变量b = {b}')
    return func3

func1()
f3 = func2()
f3(1)
print(f'函数体外的全局变量a = {a}')
print(f'函数体外的全局变量b = {b}')
print(f'函数体外的全局变量c = {c}')


# 默写一个装饰器, 用来输出函数的执行时间.
import time
# 没有闭包，func函数没法传参
def func4(func):
    start_time = time.time()
    func()
    end_time = time.time()
    print(f"{func.__name__} 函数的执行时间：{format(end_time - start_time, '.2f')} s")

@func4
def chengfang():
    count = 0
    while True:
        if count >= 20 ** 5:
            break
        else:
            count += 1
# 此时没有调用chengfang函数或者func4函数，但是依然有该函数执行的print，why?

# 优化，加上闭包
def func5(func):
    def wrapper(*args, **kwargs):
        start_time = time.time()
        func(*args, **kwargs)
        end_time = time.time()
        print(f"{func.__name__} 函数的执行时间：{format(end_time - start_time, '.2f')} s")
    return wrapper

@func5
def chengfang1(a, b):
    count = 0
    while True:
        if count >= a ** b:
            break
        else:
            count += 1
chengfang1(20, 5)

# 使用装饰器来为斐波那契函数添加缓存
def cache_deco(func):
    a = {}
    def wrapper(n):
        if n in a.keys():
            print('在缓存a字典中')
            return a[n]
        else:
            a[n] = func(n)
            print('不在缓存a字典中')
            return a[n]
    return wrapper

@cache_deco
def fibo(n):
    if n == 0 or n == 1:
        return n
    else:
        res = fibo(n - 1) + fibo(n - 2)
        return res
print(f"斐波那契函数：{fibo(1)}\n")
print(f"斐波那契函数：{fibo(1)}")